from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from itsdangerous import SignatureExpired, BadSignature

from apps.libs.error_code import Success, DeleteSuccess, AuthFailed, ParameterException
from apps.libs.redprint import Redprint
from apps.libs.services.UserService import UserService
from apps.libs.token_auth import auth, generate_auth_token
from apps.models.base import db
from apps.models.user import User
from apps.models.user_bind import UserBind

from apps.libs.helper import helper

from flask import jsonify, g, request, current_app

from apps.validators.forms import UserLoginForm, UserCheckregForm

api = Redprint('user')


@api.route('/login/', methods=['POST'])
def login():

    form = UserLoginForm().validate_for_api()
    code = form.code.data
    nickname = form.nickName.data
    sex = form.gender.data
    avatar = form.avatarUrl.data

    # 根据前端传过来的code，和appid、secret获取openid
    openid = UserService.getWechatOpenid(code)
    if not openid:
        return ParameterException(msg='调用微信出错，请重试！')

    # 根据openid判断是否已经注册过
    bindInfo = db.session.query(UserBind).filter_by(openid=openid).first()
    if bindInfo:
        userInfo = User.query.filter_by(id=bindInfo.user_id).first()
        expiration = current_app.config['TOKEN_EXPIRATION']
        token = generate_auth_token(userInfo.id, expiration)
        return Success(error_code=201, msg='已经绑定', data={'nickname': userInfo.nickname, 'token': token})
    else:
        with db.auto_commit():
            user = User()
            user.nickname = nickname
            user.avatar = avatar
            user.sex = sex
            user.email = ''
            user.mobile = ''
            user.login_name = ''
            user.updated_time = user.created_time = helper.genedatetime()
            db.session.add(user)

        with db.auto_commit():
            user_bind = UserBind()
            user_bind.user_id = user.id
            user_bind.openid = openid
            user_bind.update_time = user_bind.create_time = helper.genedatetime()
            user_bind.client_type = 'weixin'
            db.session.add(user_bind)

    # Token
    expiration = current_app.config['TOKEN_EXPIRATION']
    token = generate_auth_token(user_bind.user_id, expiration)
    return Success(msg='登录成功', data={'nickname': user.nickname, 'token': token})


@api.route('/checkreg/', methods=['POST'])
def checkreg():
    form = UserCheckregForm().validate_for_api()
    code = form.code.data

    # 根据前端传过来的code，和appid、secret获取openid
    openid = UserService.getWechatOpenid(code)
    if not openid:
        return ParameterException(msg='调用微信出错，请重试！')

    # 根据openid判断是否已经注册过
    bindInfo = db.session.query(UserBind).filter_by(openid=openid).first()
    if bindInfo:
        userInfo = User.query.filter_by(id=bindInfo.user_id).first()
        expiration = current_app.config['TOKEN_EXPIRATION']
        token = generate_auth_token(userInfo.id, expiration)
        return Success(error_code=200, msg='已经绑定',
                       data={'nickname': userInfo.nickname, 'token': token, 'avatar': userInfo.avatar,
                             'sex': userInfo.sex})
    else:
        return AuthFailed(error_code=201, msg='未认证')


@api.route('/<int:uid>', methods=['POST'])
@auth.login_required
def get_user(uid):
    user = User.query.get_or_404(uid)
    return jsonify(user)


@api.route('/delete', methods=['DELETE'])
@auth.login_required
def delete_user():
    # 防止用户超权操作
    uid = g.user.uid
    with db.auto_commit():
        user = User.query.filter_by(id=uid, status=1).first_or_404()
        user.delete()
    return DeleteSuccess()


@api.route('/<int:uid>', methods=['GET'])
@auth.login_required
def super_get_user(uid):
    is_admin = g.user.is_admin
    if not is_admin:
        raise AuthFailed()
    user = User.query.filter_by(id=uid).first_or_404()
    return jsonify(user)

@api.route('/<int:uid>', methods=['DELETE'])
@auth.login_required
def super_delete_user(uid):
    with db.auto_commit():
        user = User.query.filter_by(id=uid).first_or_404()
        user.delete()
    return DeleteSuccess()
